############# ########### ####### ##### ### ##
#
# Copyright (C) 2010 The Hursk Group, LLC
#
# This program is free software: you can redistribute it and/or modify 
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program (See file named COPYING).  If not, see 
# <http://www.gnu.org/licenses/>.
# 
############# ########### ####### ##### ### ##


BEGIN {
	month["Jan"] = "01"
	month["Feb"] = "02"
	month["Mar"] = "03"
	month["Apr"] = "04"
	month["May"] = "05"
	month["Jun"] = "06"
	month["Jul"] = "07"
	month["Aug"] = "08"
	month["Sep"] = "09"
	month["Oct"] = "10"
	month["Nov"] = "11"
	month["Dec"] = "12"
	
	# Magic date.  We don't want patches newer than this date reported
	nonewerthan = "20071125"
}

# Solaris 8 patch listing.  Each line contains something like the following:
# 112794-01

# Output in CSV:
# Needed patch, installed patch, status
# Where status is either missing, old, current
# missing: no patch was installed, but a security patch exists.  Might be a false positive
# old: an older patch than the security patch was installed
# current: the same or a newer patch was installed

# Input: showrevp output
pass==1 {
# Output: patch_inst_arr[PATCH] = REV

	installedpatch = $2
	# Record only the highest version in the array
	# showrev -p may contain more than one revision
	split(installedpatch,tmp_arr,"-")
	patch = tmp_arr[1]
	rev = tmp_arr[2]
	if ( patch_inst_arr[patch] <= rev ) {
		patch_inst_arr[patch] = rev
	}

}

# processed pkginfo long output
# PKGINST:VERSION
pass == 2 {
	pkg_inst_arr[$0] = $0
}

# uname 
pass == 3 {
# 6: sparc, i386, etc.
	my_platform = $6
}

# Input patchdiag.xref
pass == 4 {
# Output is an array, pkg_arr:
# pkg_arr[PKGINST:VERSION,counter] = PATCH-REV
# E.g. PKGINST:VERSION = SUNWsrmr:1.2.0,REV=2000.03.20.10.37 
# E.g. PATCH-REV = 100386-01

# patchdiag is complex
# XXX 
#   We are not currently following obsolete security patches to 
# make sure the updated patch is installed. If rev X has 15 
# packages, but rev Y > X has 10 packages, we are only checking 
# the packages with rev Y against the current rev (which could 
# be anwhere between (1,X,Y) or greater than Y.  That is we will 
# miss those 5 pkgs in rev X if say current rev is less than X, 
# since we only check it against rev Y.  Let your mind wander on
# this thought and think about the other scenarios that we're
# also not getting...

  # Split up the file, delimited by '|'
  # 1: Patch
  # 2: Rev
  # 3: Date
  # 4: Recommened (R)
  # 5: Security (S)
  # 6: Obsolete (O)
  # 7: Y2K baby! (Y)
  # 8: OS, Unbundled, or ""
  # 9: platform
  # 10: package
  # 11: synopsis
  if ( $0 !~ /^##/ ) {
  	split($0,tmp_arr,"|")
	# Only care about non-obsolete security patches / packages first
	#  on our hardware platform
	if ( tmp_arr[5] == "S" && tmp_arr[6] != "O" && tmp_arr[9] ~ my_platform) {
	  # Have we been here? This will only return true if we have and if
	  # the revision looked at is newer than the prior.
	  patch = tmp_arr[1]
	  rev = tmp_arr[2]
	  # Split date
	  split(tmp_arr[3],datetime,"/")
	  datetime[1] = month[datetime[1]]
	  if ( datetime[3] <= 80 ) {
		year = 2000 + datetime[3]
	  } else {
		year = 1900 + datetime[3]
	  }
	  date = year "" datetime[1] "" datetime[2]
	  # Skip patches newer than our nonewerthan variable
	  if ( date > nonewerthan ) {
		next
	  } else {
	    if ( diag_patch_arr[patch] < rev ) {
		diag_patch_arr[patch] = rev
	    	diag_date_arr[patch] = date
		# Then split the pkgarr string
		if ( tmp_arr[10] != "" ) {
		  split(tmp_arr[10],tmp_pkg_arr,";")
		  # Then create new array, stuffing at end patch info
		  for (j in tmp_pkg_arr ) {
			# Note: tmp_pkg_arr[j] == PKGINST:VERSION
			pkg_ver = tmp_pkg_arr[j]
	  		if ( pkg_ver != "" ) {
			  # Do we have an installed package?
			  if ( pkg_inst_arr[pkg_ver] == pkg_ver ) {
				#print "DEBUG: pkg_ver:" pkg_ver"\t patch: "patch
				# If first time, add 
				if ( diag_pkg_arr[patch] == "" ) {
		  			diag_pkg_arr[patch] = pkg_ver
				} else {  # else append
		  			diag_pkg_arr[patch] = diag_pkg_arr[patch] "\t" pkg_ver
				}
			  } else {
				continue
			  }
			}
		  }
		} else {
			next
		}
	    }
	  }
	}
  }
}


END {
# print out the following:
# ip \t PKGINST \t PATCH \t Installed REV \t Security REV \t issue?
# where issue can be:
#  old
#  current
#  missing
#  false positive (manually entered)
  # Does the package exist?

  # enumerate through all of the possible packages
  # which also happen to be installed
  for ( patch in diag_pkg_arr ) {
	#split(diag_pkg_arr[patch],tmp_pkg_arr,"\t")
	req_rev = diag_patch_arr[patch]
	inst_rev = patch_inst_arr[patch]
	date = diag_date_arr[patch]
	if (inst_rev == "" ) inst_rev = "00"
	if ( req_rev > inst_rev ) {
		issue = "missing"
	} else {
		issue = "current"	
	}
	#for ( pkg in tmp_pkg_arr ) {
		#print ip "\t" date "\t" patch "\t" req_rev "\t" inst_rev "\t"issue "\t" tmp_pkg_arr[pkg]
		print ip "," date "," patch "," req_rev "," inst_rev "," issue
	#}
	}
}

